from django.shortcuts import render
from django.utils import timezone
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect, Http404
from . import models
from comment.models import Comment
from .forms import EditForm
from comment.forms import CommentForm
from django.db import transaction


def getDifOfTags(oldTags, newTags):
    oldSet = set(oldTags)
    newSet = set(newTags)

    oldDif = oldSet - newSet
    newDif = newSet - oldSet

    return oldDif, newDif


# Create your views here.
@login_required
@transaction.atomic
def EditView(request):
    if request.method == 'POST':
        form = EditForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data['title']
            tags = form.cleaned_data['tags']
            tags = tags.split('|')
            abstract = form.cleaned_data['abstract']
            body = form.cleaned_data['content']
            author = request.user
            status = 'P' if request.POST.get("submit") == "publish" else 'D'
            newArticle = models.Article(
                title=title,
                abstract=abstract,
                body=body,
                author=author,
                status=status
            )
            newArticle.save()

            for ele in tags:
                tag, _ = models.Tag.objects.get_or_create(content=ele)
                newRelation = models.Article2Tags(
                    article=newArticle,
                    tag=tag
                )
                newRelation.save()

            path = "/blog/archieve/" + request.user.username
            return HttpResponseRedirect(path)
    else:
        form = EditForm(request.POST)
        return render(request, 'blog/edit.html', {'form': form})


@login_required
@transaction.atomic
def UpdateView(request, aid):
    try:
        article = models.Article.objects.get(aid=aid)
    except models.Article.DoesNotExist:
        raise Http404("No article matches the given query.")
    if request.user != article.author:
        raise PermissionDenied
    if request.method == 'POST':
        form = EditForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data['title']
            tags = form.cleaned_data['tags']
            tags = tags.split('|')
            tags = list(set(tags))[0:6]
            abstract = form.cleaned_data['abstract']
            body = form.cleaned_data['content']
            status = 'P' if request.POST.get("submit") == "publish" else 'D'

            article.title = title
            article.abstract = abstract
            article.body = body
            article.status = status
            article.updatedAt = timezone.now()
            article.save()

            oTags = models.Article2Tags.objects.filter(article__aid=aid)
            oldTags = [ele.tag.content for ele in oTags]
            oldDif, newDif = getDifOfTags(oldTags, tags)
            for tag in oldDif:
                qset = models.Article2Tags.objects.filter(
                    article__aid=aid, tag__content=tag
                )
                qset.delete()

            for ele in tags:
                tag, created = models.Tag.objects.get_or_create(content=ele)

            for tag in newDif:
                tag = models.Tag.objects.get(content=tag)
                newRelation = models.Article2Tags(
                    article=article,
                    tag=tag
                )
                newRelation.save()

            path = "/blog/archieve/" + request.user.username
            return HttpResponseRedirect(path)
    else:
        form = EditForm(request.POST)

        # 获取 tags 字符串
        oTags = models.Article2Tags.objects.filter(article__aid=aid)
        tagStr = '|'.join([item.tag.content for item in oTags])

        return render(request, 'blog/update.html', {
            'form': form,
            'article': article,
            'tags_str': tagStr
        })


@login_required
@transaction.atomic
def DeleteView(request, aid):
    try:
        article = models.Article.objects.get(aid=aid)
    except models.Article.DoesNotExist:
        raise Http404("No article matches the given query.")
    if request.user != article.author:
        raise PermissionDenied
    else:
        article.delete()
        path = "/blog/archieve/" + request.user.username
        return HttpResponseRedirect(path)


'''
使用基于类的视图时，可以使用 LoginRequiredMixin 实现和 login_required 相同的行为。
这个 Mixin 应该在继承列表中最左侧的位置。
'''


# 文章归档视图
class ArchieveView(LoginRequiredMixin, ListView):
    model = models.Article
    paginate_by = 5
    template_name = "blog/archieve.html"
    context_object_name = "article_list"

    # 重写查询集
    def get_queryset(self, **kwargs):
        # 从 url 取参数
        usrname = self.kwargs['usrname']
        # 双下划线表示字段查询
        return models.Article.objects.filter(
            author__username=usrname,
            status='P'
        ).order_by("-updatedAt")

    # 重写上下文获取子方法
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.user.username == self.kwargs['usrname']:
            # owner 成为模板变量之一
            context['owner'] = True
        else:
            context['owner'] = False
        current_user = self.request.user
        context['current_user'] = current_user
        context['published'] = True
        return context


# 草稿箱视图
class DraftsView(LoginRequiredMixin, ListView):
    model = models.Article
    paginate_by = 5
    template_name = "blog/archieve.html"
    context_object_name = "article_list"

    def dispatch(self, request, *args, **kwargs):
        usrname = self.kwargs['usrname']
        if request.user.username != usrname:
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get_queryset(self, **kwargs):
        usrname = self.kwargs['usrname']
        return models.Article.objects.filter(
            author__username=usrname,
            status='D'
        ).order_by("-updatedAt")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        current_user = self.request.user
        context['current_user'] = current_user
        context['published'] = False
        return context


# 文章详情页视图
class ArticleDetailView(LoginRequiredMixin, DetailView):
    model = models.Article
    template_name = "blog/article_detail.html"
    context_object_name = "article"

    def dispatch(self, request, *args, **kwargs):
        # usrname = self.kwargs['usrname']
        aid = self.kwargs['aid']
        try:
            self.kwargs['model'] = models.Article.objects.get(aid=aid)
        except models.Article.DoesNotExist:
            raise Http404("No article matches the given query.")
        if self.kwargs['model'].status == 'D' \
                and request.user.username != \
                self.kwargs['model'].author.username:
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get_object(self, queryset=None):
        return self.kwargs['model']

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        aid = self.kwargs['aid']
        tags = models.Article2Tags.objects.filter(article__aid=aid)
        comments = Comment.objects.filter(article__aid=aid)
        form = CommentForm()

        tags = [ele.tag.content for ele in tags]
        context['form'] = form
        context['tags'] = tags
        context['comments'] = comments
        current_user = self.request.user
        context['current_user'] = current_user
        if self.request.user.username == self.kwargs['usrname']:
            context['owner'] = True
        else:
            context['owner'] = False
        return context
